package main;

import static com.googlecode.javacv.cpp.opencv_core.IPL_DEPTH_8U;
import static com.googlecode.javacv.cpp.opencv_core.cvCreateImage;
import static com.googlecode.javacv.cpp.opencv_core.cvFlip;
import static com.googlecode.javacv.cpp.opencv_core.cvGetSize;
import static com.googlecode.javacv.cpp.opencv_core.cvInRangeS;
import static com.googlecode.javacv.cpp.opencv_core.cvScalar;
import static com.googlecode.javacv.cpp.opencv_highgui.CV_CAP_ANY;
import static com.googlecode.javacv.cpp.opencv_highgui.cvCreateCameraCapture;
import static com.googlecode.javacv.cpp.opencv_highgui.cvQueryFrame;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_BGR2HSV;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_CHAIN_APPROX_SIMPLE;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_MOP_DILATE;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_MOP_ERODE;
import static com.googlecode.javacv.cpp.opencv_imgproc.CV_RETR_LIST;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvCvtColor;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvFindContours;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvGetCentralMoment;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvGetSpatialMoment;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvMinAreaRect2;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvMoments;
import static com.googlecode.javacv.cpp.opencv_imgproc.cvMorphologyEx;
import game.BreakoutPanel;

import java.awt.AWTException;
import java.awt.Container;
import java.awt.Robot;

import javax.swing.JFrame;

import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.cpp.opencv_core.CvBox2D;
import com.googlecode.javacv.cpp.opencv_core.CvContour;
import com.googlecode.javacv.cpp.opencv_core.CvMemStorage;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;
import com.googlecode.javacv.cpp.opencv_core.CvSize2D32f;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_highgui.CvCapture;
import com.googlecode.javacv.cpp.opencv_imgproc.CvMoments;

public class MainApp implements Runnable {
	
	static double hue_min = 0;
	static double hue_max = 0;
	static double sat_min = 0;
	static double sat_max = 0;
	static double val_min = 0;
	static double val_max = 0;
	static CvCapture capture;
	static CvMemStorage storage;
	//CvScalar rgba_min = cvScalar(0, 0, 130, 0);
	//CvScalar rgba_max = cvScalar(80, 80, 255, 0);
	IplImage image;
	static CanvasFrame canvas = new CanvasFrame("Detection");
	
	public MainApp() {
        canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    }
	

	public static void main(String[] args) {
		
		storage = CvMemStorage.create();
		
		JFrame frame = new JFrame("Breakout Game");
		frame.setSize(500,500);
		frame.setResizable(false);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		BreakoutPanel bPanel = new BreakoutPanel(500,500);
		Container pane = frame.getContentPane();
		pane.add(bPanel);
		frame.setVisible(true);
		MainApp app = new MainApp();
		Thread th = new Thread(app);
        th.start();
	}
	
	private static void track(CvSeq maxCont) {
		CvMoments moments = new CvMoments();
		cvMoments(maxCont, moments, 1);
		
		 double moment10 = cvGetSpatialMoment(moments, 1, 0);
		 double moment01 = cvGetSpatialMoment(moments, 0, 1);
		 double area = cvGetCentralMoment(moments, 0, 0);
		 
		 if(area > 400) {
			 int posX = (int)(moment10/area);
		     int posY = (int)(moment01/area);   
		     if (posX > 0 && posY > 0 && GUI.getInstance().isPlaying()) {
               Robot r;
			try {
				r = new Robot();
				r.mouseMove(posX, posY);
			} catch (AWTException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
               
           }
		    // System.out.println(posX + " " + posY);
		 }
	}
	
	private static CvSeq findBiggestContour(IplImage imgbin) {
		
		CvSeq maxCont = null;
		CvSeq contours = new CvSeq(null);
		cvFindContours(imgbin, storage, contours, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
		
		float maxArea = 200f;
		  while (contours != null && !contours.isNull()) {
		    if (contours.elem_size() > 0) {
		      CvBox2D box = cvMinAreaRect2(contours, storage);
		      if (box != null) {
		        CvSize2D32f size = box.size();
		        float area = size.width() * size.height();
		        if (area > maxArea) {
		          maxArea = area;
		          maxCont = contours;
		        }
		      }
		    }
		    contours = contours.h_next();
		  }

		
		return maxCont;
	}

	@Override
	public void run() {
		capture = cvCreateCameraCapture(CV_CAP_ANY);
		
		IplImage capFrame = null;
		IplImage imgbin = null;
		
		canvas = new CanvasFrame("Detection");
		
		while(canvas.isVisible()) {
			
			capFrame = cvQueryFrame(capture); // captured frame from camera
			if(capFrame == null)
				break;
			
			imgbin = cvCreateImage(cvGetSize(capFrame), IPL_DEPTH_8U, 1);
			
			cvCvtColor(capFrame, capFrame, CV_BGR2HSV);
			
			//get values from sliders
			hue_min = GUI.getInstance().getHUE_MIN();
			hue_max = GUI.getInstance().getHUE_MAX();
			
			sat_min = GUI.getInstance().getSAT_MIN();
			sat_max = GUI.getInstance().getSAT_MAX();
			
			val_min = GUI.getInstance().getVAL_MIN();
			val_max = GUI.getInstance().getVAL_MAX();
			
			cvInRangeS(capFrame, cvScalar(hue_min, sat_min, val_min, 0) , cvScalar(hue_max, sat_max, val_max, 0), imgbin);
			
			cvMorphologyEx(imgbin, imgbin, null, null, CV_MOP_ERODE, 1);
			cvMorphologyEx(imgbin, imgbin, null, null, CV_MOP_DILATE, 3);
			
			cvFlip(imgbin, imgbin, 1);
			CvSeq maxCont = findBiggestContour(imgbin);
			
			
			if(maxCont != null)
				track(maxCont);
			canvas.showImage(imgbin);

		}
	}
	
}